package objects;

import static objects.AdapletConstants.sNewLine;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import objects.AdapletConstants.ColumnType;
import sections.ISection.Section;

public class Table implements IObject
{
	/**
	 * 
	 */
	private static final long serialVersionUID = -8788686263787767203L;
	private String fTableName;
	private Map<String, ColumnType> fColumnDefinitions;
	private Map<String, Integer> fLargeStringSizes;

	public Table()
	{
		fTableName = "";
		fColumnDefinitions = new LinkedHashMap<String, ColumnType>();
		fLargeStringSizes = new HashMap<String, Integer>();
	}

	public String buildTableDefinition()
	{
		StringBuffer tableDefinition = new StringBuffer(1000);

		tableDefinition.append("table ");
		tableDefinition.append(fTableName);
		tableDefinition.append(" {");
		tableDefinition.append(sNewLine);

		for (String columnName : fColumnDefinitions.keySet())
		{
			ColumnType colType = fColumnDefinitions.get(columnName);
			tableDefinition.append("\t");
			tableDefinition.append(columnName);
			tableDefinition.append("\t\t");
			tableDefinition.append(columnTypeToString(columnName, colType));
			tableDefinition.append(";");
			tableDefinition.append(sNewLine);
		}

		tableDefinition.append("}");
		tableDefinition.append(sNewLine);

		return tableDefinition.toString();
	}

	private String columnTypeToString(String columnName, ColumnType colType)
	{
		StringBuffer stringValue = new StringBuffer(20);
		switch (colType)
		{
		case DATE:
			stringValue.append("date");
			break;
		case INT:
			stringValue.append("int");
			break;
		case LONG:
			stringValue.append("long");
			break;
		case LARGESTRING:
			Integer size = fLargeStringSizes.get(columnName);
			if (size != null)
			{
				stringValue.append("largestring ");
				stringValue.append(size);
			}
			else
			{
				stringValue.append("string");
			}
			break;
		case RAW:
			stringValue.append("raw");
			break;
		case REAL:
			stringValue.append("real");
			break;
		case STRING:
			stringValue.append("string");
			break;
		}
		return stringValue.toString();
	}

	public String getTableName()
	{
		return fTableName;
	}

	public void setTableName(String tableName)
	{
		this.fTableName = tableName;
	}

	public void addColumn(String columnName, ColumnType colType, int largeStringSize)
	{
		fColumnDefinitions.put(columnName, colType);

		if (colType == ColumnType.LARGESTRING)
		{
			fLargeStringSizes.put(columnName, largeStringSize);
		}
	}

	@Override
	public String toString()
	{
		return buildTableDefinition();
	}

	@Override
	public String getObjectName()
	{
		return getTableName();
	}

	@Override
	public Section getSectionType()
	{
		return Section.TABLE;
	}

	public String[] getColumnNames()
	{
		return fColumnDefinitions.keySet().toArray(new String[0]);
	}

	public ColumnType[] getColumnTypes()
	{
		return fColumnDefinitions.values().toArray(new ColumnType[0]);
	}

	public String[] getLargeStringColumns()
	{
		return fLargeStringSizes.keySet().toArray(new String[0]);
	}

	public Integer[] getLargeStringSizes()
	{
		return fLargeStringSizes.values().toArray(new Integer[0]);
	}

	public String getSizeForLargeColumn(String sColName)
	{
		return fLargeStringSizes.get(sColName).toString();
	}

	public ColumnType getTypeForColumn(String sColName)
	{
		return fColumnDefinitions.get(sColName);
	}

	private void readObject(ObjectInputStream iStream) throws IOException, ClassNotFoundException
	{
		iStream.defaultReadObject();
		validateState();
	}

	private void writeObject(ObjectOutputStream oStream) throws IOException
	{
		oStream.defaultWriteObject();
	}

	private void validateState()
	{
		if (fTableName == null || fTableName.isEmpty())
		{
			throw new IllegalArgumentException("Table Name cannot be null or empty.");
		}
		else if (fColumnDefinitions == null)
		{
			throw new IllegalArgumentException("Column Definitions cannot be null.");
		}
		else if (fLargeStringSizes == null)
		{
			throw new IllegalArgumentException("Large Strings set cannot be null");
		}
		else
		{
			int lStringCount = fLargeStringSizes.size();

			int colCount = 0;
			for (ColumnType type : fColumnDefinitions.values())
			{
				if (type == ColumnType.LARGESTRING)
				{
					colCount++;
				}
			}

			if (lStringCount != colCount)
			{
				throw new IllegalArgumentException(
						"The number of Columns defined as large strings should match the number of large string sizes");
			}
		}
	}
}
